package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.Voucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.service.IVoucherService;
import com.hmdp.utils.RedisWorker;
import com.hmdp.utils.SimpleRedisLock;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Resource
    private ISeckillVoucherService iSeckillVoucherService;


    @Resource
    private RedisWorker redisWorker;

    @Resource
    private StringRedisTemplate stringRedisTemplate;


//    @Resource
//    private VoucherOrderServiceImpl voucherOrderService;

    /**
     * 抢购优惠券
     *
     * @param voucherId
     * @return
     */
    @Override
    public Result seckillVoucher(Long voucherId) {
        // 查询优惠券信息
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        if (!BeanUtil.isNotEmpty(voucher)) {
            return Result.fail("查询优惠券错误！");
        }
        // 判断是否开始
        // 2023-11-11 2023-11-10 == true
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            // 未到开始时间
            return Result.fail("秒杀暂未开始");
        }
        // 判断是否结束
        //  2023-11-10 2023-11-11 == false
        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            return Result.fail("秒杀已结束");
        }
        // 判断库存是否充足
        if (voucher.getStock() < 1) {
            return Result.fail("存库不足,尽情期待下次活动开始~");
        }
        long userID = UserHolder.getUser().getId();
        // 分布式解决方案
        SimpleRedisLock lock = new SimpleRedisLock(stringRedisTemplate, "order:" + userID);
        boolean isLock = lock.tryLock(1200);
        if (!isLock) {
            // 获取失败
            return Result.fail("一人一单");
        }
        try {
            IVoucherOrderService service = (IVoucherOrderService) AopContext.currentProxy();
            return service.createVoucherOrder(voucherId);
        } finally {
            lock.unlock();
        }
    }

    private Result MonolithicArchitectureImplementation(Long voucherId) {
        // 查询优惠券信息
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        if (!BeanUtil.isNotEmpty(voucher)) {
            return Result.fail("查询优惠券错误！");
        }
        // 判断是否开始
        // 2023-11-11 2023-11-10 == true
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            // 未到开始时间
            return Result.fail("秒杀暂未开始");
        }
        // 判断是否结束
        //  2023-11-10 2023-11-11 == false
        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            return Result.fail("秒杀已结束");
        }
        // 判断库存是否充足
        if (voucher.getStock() < 1) {
            return Result.fail("存库不足,尽情期待下次活动开始~");
        }

        /**
         * toString的底层实现是每次一个对象进来都是new一个新的,因此就算同一个用户进来也是一个新的对象
         */
        Long userId = UserHolder.getUser().getId();
        synchronized (userId.toString().intern()) {
            // 事务生效问题
            IVoucherOrderService service = (IVoucherOrderService) AopContext.currentProxy();
//            return voucherOrderService.createVoucherOrder(voucherId);
//            return createVoucherOrder(voucherId);
            return service.createVoucherOrder(voucherId);
        }
    }


    /**
     * 悲观锁实现,锁的力度为用户,同一个用户只允许下一单
     *
     * @param voucherId
     * @return
     */
    @Transactional
    public Result createVoucherOrder(Long voucherId) {
        Long userId = UserHolder.getUser().getId();

        // 一人一单
        //判断用户是否下过单
        int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
        if (count > 0) {
            return Result.fail("不能重复领取!");
        }
        // 扣减库存
        // 乐观锁解决
        boolean success = iSeckillVoucherService.update()
                .setSql("stock = stock - 1 ")
                .eq("voucher_id", voucherId).gt("stock", 0).update(); // stock > 0 即可
        if (!success) {
            return Result.fail("扣减库存失败!");
        }
        // 创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        voucherOrder.setId(redisWorker.nextId("order"));
        voucherOrder.setUserId(userId);
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        // 返回订单ID
        return Result.ok(voucherOrder.getId());
    }


    /**
     * 乐观锁的方式解决高并发,单体架构
     *
     * @param voucherId
     * @return
     */
    @Transactional
    public Result optimisticLock(Long voucherId) {
        // 查询优惠券信息
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        if (!BeanUtil.isNotEmpty(voucher)) {
            return Result.fail("查询优惠券错误！");
        }
        // 判断是否开始
        // 2023-11-11 2023-11-10 == true
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            // 未到开始时间
            return Result.fail("秒杀暂未开始");
        }
        // 判断是否结束
        //  2023-11-10 2023-11-11 == false
        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            return Result.fail("秒杀已结束");
        }
        // 判断库存是否充足
        if (voucher.getStock() < 1) {
            return Result.fail("存库不足,尽情期待下次活动开始~");
        }
        // 扣减库存
//        boolean success = iSeckillVoucherService.update()
//                .setSql("stock = stock - 1 ")
//                // 乐观锁成功率太低
//                .eq("voucher_id", voucherId).eq("stock", voucher.getStock()).update();
        // 乐观锁解决
        boolean success = iSeckillVoucherService.update()
                .setSql("stock = stock - 1 ")
                .eq("voucher_id", voucherId).gt("stock", 0).update(); // stock > 0 即可
        if (!success) {
            return Result.fail("扣减库存失败!");
        }
        // 创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        voucherOrder.setId(redisWorker.nextId("order"));
        voucherOrder.setUserId(UserHolder.getUser().getId());
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        // 返回订单ID
        return Result.ok(voucherOrder.getId());
    }
}
